﻿using System.Collections.Generic;
using Engine;
using Engine.Graphics;
using Game;

namespace Mekiasm
{
    public abstract class MekBlock : Block
    {
        public enum DeviceType
        {
            None, Electric, Fluid, Gas, Item, Plant
        }

        public enum MachineMode
        {
            IN, 
            OUT, 
            ALLSAME
        }

        public Dictionary<int,Item> blocks = new Dictionary<int, Item>();

        public virtual Item GetItem(ref int value)
        {
            //id最大255
            int itemIndex = ILibrary.GetItemId(value);
            Item item = blocks[itemIndex];
            return item;
        }

        public virtual void AddItem(Item item)
        {
            item.itemIndex = blocks.Count;
            item.blockValue = item.MakeBlockValue(BlockIndex, item.itemIndex);
            var type = item.GetType();
            var indexAttribute = type.GetField("Index", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
            if (indexAttribute != null)
            {
                indexAttribute.SetValue(item, item.blockValue);
            }
            blocks.Add(item.itemIndex, item);
        }
        public bool IsFood(int value)
        {
            return GetItem(ref value).IsFood();
        }
        public virtual bool OnHitAsProjectile(CellFace? cellFace, ComponentBody componentBody, WorldItem worldItem)
        {
            return GetItem(ref worldItem.Value).OnHitAsProjectile(cellFace, componentBody, worldItem);
        }
        public override float GetNutritionalValue(int value)
        {
            return GetItem(ref value).GetNutritionalValue();
        }
        public override ClothingData GetClothingData(int value)
        {
            return GetItem(ref value).GetClothingData();
        }
        public override bool CanWear(int value)
        {
            return GetItem(ref value).IsClothing();
        }


        public override void Initialize()
        {
            IsTransparent = true;
            IsAimable = false;
            IsNonDuplicable = false;
            IsFluidBlocker = true;
            ToolLevel = 0;
            RequiredToolLevel = 0;
            DigResilience = 6f;
            DigMethod = BlockDigMethod.Shovel;
            ShovelPower = 0f;
            DefaultIconViewOffset = new Vector3(1f);
            FirstPersonScale = 0.3f;
            FirstPersonOffset = new Vector3(0.5f, -0.5f, -0.6f);
            FirstPersonRotation = new Vector3(0f, 60f, 0f);
            InHandScale = 0.3f;
            InHandRotation = new Vector3(0f, 0f, 45f);
            InHandOffset = new Vector3(0f, 0.12f, 0f);
            DefaultEmittedLightAmount = 15;
            LightAttenuation = 0;
            DefaultShadowStrength = 0;
            CraftingId = GetType().FullName;

        }
        /// <summary>
        /// 获取合成后剩下的物品值
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual int GetCraftedRemainValue(int value)
        {
            return GetItem(ref value).GetCraftedRemainValue(value);
        }
        /// <summary>
        /// 获取合成结果的值
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual int GetCraftedResultValue(int value)
        {
            return GetItem(ref value).GetCraftedResultValue(value);
        }
        public override IEnumerable<CraftingRecipe> GetProceduralCraftingRecipes()
        {
            List<CraftingRecipe> recipes = new List<CraftingRecipe>();
            foreach (int v in GetCreativeValues())
            {
                int vv = v;
                GetItem(ref vv).GetProceduralCraftingRecipes(recipes);
            }
            return recipes.ToArray();
        }
        public override BlockPlacementData GetDigValue(SubsystemTerrain subsystemTerrain, ComponentMiner componentMiner, int value, int toolValue, TerrainRaycastResult raycastResult)
        {
            return GetItem(ref value).GetDigValue(subsystemTerrain, componentMiner, value, toolValue, raycastResult);
        }
        public override Vector3 GetFirstPersonRotation(int value)
        {
            return GetItem(ref value).GetFirstPersonRotation(value);
        }
        public override Vector3 GetFirstPersonOffset(int value)
        {
            return GetItem(ref value).GetFirstPersonOffset(value);
        }
        public override Vector3 GetInHandRotation(int value)
        {
            return GetItem(ref value).GetInHandRotation(value);
        }
        public override Vector3 GetInHandOffset(int value)
        {
            return GetItem(ref value).GetInHandOffset(value);
        }

        public bool Collidable(int value)
        {
            return GetItem(ref value).IsCollidable(value);
        }
        public override float GetBlockHealth(int value)
        {
            return GetItem(ref value).GetBlockHealth(value);
        }
        public override int GetTextureSlotCount(int value)
        {
            return GetItem(ref value).GetTextureSlotCount(value);
        }
        public override bool IsInteractive(SubsystemTerrain subsystemTerrain, int value)
        {
            return GetItem(ref value).IsInteractive(subsystemTerrain, value);
        }
        public override int GetEmittedLightAmount(int value)
        {
            return GetItem(ref value).GetEmittedLightAmount(value);
        }
        public override BlockPlacementData GetPlacementValue(SubsystemTerrain subsystemTerrain, ComponentMiner componentMiner, int value, TerrainRaycastResult raycastResult)
        {
            return GetItem(ref value).GetPlacementValue(subsystemTerrain, componentMiner, value, raycastResult);
        }
        public virtual void OnHandOut(ComponentPlayer player, int oldValue,int newValue)
        {
            var o = GetItem(ref oldValue);
            var n = GetItem(ref newValue);
            if (o != n)
            {
                o.OnHandOut(player, oldValue, newValue);
                n.OnHandIn(player, oldValue, newValue);
            }
        }
        public virtual void OnHand(ComponentPlayer player, int value)
        {
            GetItem(ref value).OnHand(player, value);
        }
        public Texture2D GetTexture(int value)
        {
            return GetItem(ref value).GetTexture();
        }
        public DeviceType GetDeviceType(int value)
        {
            return GetItem(ref value).GetDeviceType();
        }
        public virtual bool AllowConfigure(int face, int value)
        {
            return GetItem(ref value).AllowConfigure(face, value);
        }
        public virtual void OnBlockModified(int value, int oldValue, int x, int y, int z)
        {
            GetItem(ref value).OnBlockModified(value, oldValue, x, y, z);
        }
        public virtual void OnHitByProjectile(CellFace cellFace, WorldItem worldItem, int value)
        {
            GetItem(ref value).OnHitByProjectile(cellFace, worldItem);
        }
        public void OnBlockGenerated(int value, int x, int y, int z, bool isLoaded)
        {
            GetItem(ref value).OnBlockGenerated(value, x, y, z, isLoaded);
        }
        public virtual bool OnEditBlock(int x, int y, int z, int value, ComponentPlayer componentPlayer)
        {
            return GetItem(ref value).OnEditBlock(x, y, z, value, componentPlayer);
        }
        public void OnNeighborBlockChanged(int value, int x, int y, int z, int neighborX, int neighborY, int neighborZ)
        {
            GetItem(ref value).OnNeighborBlockChanged(x, y, z, neighborX, neighborY, neighborZ);
        }
        public override Vector3 GetIconBlockOffset(int value, DrawBlockEnvironmentData environmentData)
        {
            return GetItem(ref value).GetIconBlockOffset(value, environmentData);
        }
        public override bool IsFaceTransparent(SubsystemTerrain subsystemTerrain, int face, int value)
        {
            return GetItem(ref value).IsFaceTransparent(subsystemTerrain, face, value);
        }
        public override int GetShadowStrength(int value)
        {
            return GetItem(ref value).GetShadowStrength(value);
        }
        public override string GetSoundMaterialName(SubsystemTerrain subsystemTerrain, int value)
        {
            return GetItem(ref value).GetSoundMaterialName(subsystemTerrain, value);
        }
        public override Vector3 GetIconViewOffset(int value, DrawBlockEnvironmentData environmentData)
        {
            return GetItem(ref value).GetIconViewOffset(value, environmentData);
        }
        public override bool ShouldGenerateFace(SubsystemTerrain subsystemTerrain, int face, int value, int neighborValue)
        {
            return GetItem(ref value).ShouldGenerateFace(subsystemTerrain, face, value, neighborValue);
        }
        public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
        {
            return GetItem(ref value).CreateDebrisParticleSystem(subsystemTerrain, position, value, strength);
        }

        public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
        {
            GetItem(ref value).DrawBlock(primitivesRenderer, value, color, size, ref matrix, environmentData);
        }
        public virtual int GetMaxPower(int value)
        {
            return GetItem(ref value).GetMaxPower();
        }
        public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
        {
            int value = oldValue;
            GetItem(ref value).GetDropValues(subsystemTerrain, oldValue, newValue, toolLevel, dropValues, out showDebris);
        }
        public override IEnumerable<int> GetCreativeValues()
        {
            List<int> list = new List<int>();
            foreach (Item item in blocks.Values)
            {
                int value = item.blockValue;
                if (item.IsVisible(value)) list.Add(value);
            }
            return list;
        }
        public int GetBasePower(int value)
        {
            return GetItem(ref value).GetBasePower();
        }
        public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
        {
            GetItem(ref value).GenerateTerrainVertices(this, generator, geometry, value, x, y, z);
        }
        public override int GetFaceTextureSlot(int face, int value)
        {
            return GetItem(ref value).GetFaceTextureSlot(face, value);
        }
        public override string GetCategory(int value)
        {
            return GetItem(ref value).GetCategory(value);
        }
        public override string GetDisplayName(SubsystemTerrain subsystemTerrain, int value)
        {
            return GetItem(ref value).GetDisplayName(subsystemTerrain, value);
        }
        public override string GetDescription(int value)
        {
            return GetItem(ref value).GetDescription(value);
        }
        public float GetPercent(int value)
        {
            SaveItemSystem.GetBlockData(value, out Common.SaveItem toolSaveItem);
            if (toolSaveItem == null) return -1f;
            return (float)toolSaveItem.fuelAmount / GetMaxPower(value);
        }
        public bool IsCrushWhenNoPower(int value)
        {
            return GetItem(ref value).IsCrushWhenNoPower();
        }

        public override bool Eat(ComponentVitalStats v, int value)
        {
            return GetItem(ref value).Eat(v, value);
        }

        public override int GetMaxStacking(int value)
        {
            return GetItem(ref value).GetMaxStacking();
        }

        public virtual void OnBlockAdded(SubsystemBlockBehavior blockBehavior, int value, int oldValue, int x, int y, int z)
        {
            GetItem(ref value).OnBlockAdded(blockBehavior, value, oldValue, x, y, z);
        }
        public virtual void OnBlockRemoved(SubsystemBlockBehavior blockBehavior, int value, int newValue, int x, int y, int z)
        {
            GetItem(ref value).OnBlockRemoved(blockBehavior, value, newValue, x, y, z);
        }
        public virtual bool OnInteract(SubsystemBlockBehavior blockBehavior, int value, TerrainRaycastResult raycastResult, ComponentMiner componentMiner)
        {
            return GetItem(ref value).OnInteract(blockBehavior, raycastResult, componentMiner);
        }
        public virtual void OnCollide(int value, CellFace cellFace, float velocity, ComponentBody componentBody)
        {
            GetItem(ref value).OnCollide(cellFace, velocity, componentBody);
        }
        public virtual bool OnUse(Ray3 aim, ComponentMiner componentMiner, TerrainRaycastResult? raycast)
        {
            int value = componentMiner.ActiveBlockValue;
            return GetItem(ref value).OnUse(aim, componentMiner, raycast);
        }
        public virtual bool OnAim(int value, Ray3 aim, ComponentMiner componentMiner, AimState state)
        {
            return GetItem(ref value).OnAim(aim, componentMiner, state);
        }
        public virtual bool OnDigged(int value, ComponentMiner componentMiner, TerrainRaycastResult raycastResult)
        {
            return GetItem(ref value).OnDigged(value, componentMiner, raycastResult);
        }

        public override float GetShovelPower(int value)
        {
            return GetItem(ref value).GetShovelPower(value);
        }
        public override BlockDigMethod GetBlockDigMethod(int value)
        {
            return GetItem(ref value).GetDigMethod(value);
        }
        public override float GetQuarryPower(int value)
        {
            return GetItem(ref value).GetQuarryPower(value);
        }
        public override float GetHackPower(int value)
        {
            return GetItem(ref value).GetHackPower(value);
        }
        public virtual bool HasExtraSet(int value)
        {
            return GetItem(ref value).HasExtraSet(value);
        }
        public virtual void ClickExtraSet(ComponentPlayer player, int value)
        {
            GetItem(ref value).ClickExtraSet(player,value);
        }
        public override bool GetExplosionIncendiary(int value)
        {
            return GetItem(ref value).GetExplosionIncendiary(value);
        }
        public override float GetExplosionPressure(int value)
        {
            return GetItem(ref value).GetExplosionPressure(value);
        }
        public virtual BlockDigMethod GetDigMethod(int value)
        {
            return GetItem(ref value).GetDigMethod(value);
        }
        public override float GetDigResilience(int value)
        {
            return GetItem(ref value).GetDigResilience(value);
        }
        public virtual bool OnEditInventoryItem(int value, IInventory inventory, int slotIndex, ComponentPlayer componentPlayer)
        {
            return GetItem(ref value).OnEditInventoryItem(value, inventory, slotIndex, componentPlayer);
        }
        public override bool IsPlaceable_(int value)
        {
            return GetItem(ref value).IsPlaceable_(value);
        }
    }
}
